#include "stdafx.h"
#ifndef DSA_SYSTEM_CPP  
#define DSA_SYSTEM_CPP  


#include "DSA_System.h"


DSA_System::DSA_System()
{
	srand(unsigned(time(NULL)));
	generate_parameters();
}

#include "..\Lab3_Primality_test\poklington_test.h"
void DSA_System::generate_parameters()
{
	const size_t N = 32;
	const size_t L = sizeof(large_uint)*8;
	poklington pokl;
    //printf("Finding the q\n");
	q = pokl.get_prime(N); // get the N-bit number q
	//printf("q =  %lld\n", q._l);
	do
	{
		//printf("Finding the p\n");
		p = pokl.get_prime(q, L); // get the L-bit number p
		//printf("q = (%I64u; %I64u)\n", p._h, p._l);
	}
	while((p-1) % q != 0); // such as q \ (p - 1)

	unsigned int h = 2;
	do
	{
		g = large_uint::pow_m(h++, (p-1) / q, p);
	}
	while(g == 1);
	/*
	large_uint division = (p - 1) % q;
	large_uint degree = large_uint::pow_m(g, q, p);
	printf("\n\n (p - 1) / q = (%I64u; %I64u)\n\n", division._h, division._l);
	printf("\n\n g ^ q mod p = (%I64u; %I64u)\n\n", degree._h, degree._l);
	*/
}



const DSA_signer& DSA_System::add_signer()
{
	DSA_signer* s = new DSA_signer(this);
	_signers.push_back(s);
	return *s;
}
const DSA_signer& DSA_System::add_signer(const large_uint& private_key)
{
	DSA_signer* s = new DSA_signer(private_key, this);
	_signers.push_back(s);
	return *s;
}

void DSA_System::remove_signer(const size_t signer_index)
{
	DSA_signer* signer = *(_signers.begin() + signer_index);
	delete signer;
	_signers.erase(_signers.begin() + signer_index);
}


bool DSA_System::verify(const size_t signer_index, const large_uint &message_hash, const DSA_signature signature)
{

	if(
		(signature.r > 0) && (signature.r < q) && 
		(signature.s > 0) && (signature.s < q)
	  )
	{
		large_uint w = signature.s.inv(q);
		large_uint u1 = large_uint::mult_m(message_hash, w, q);
		large_uint u2 = large_uint::mult_m(signature.r, w, q);
		large_uint v =  
			large_uint::mult_m(
				large_uint::pow_m(g, u1, p), 
				large_uint::pow_m((*(_signers.begin() + signer_index))->get_public() , u2, p),
			p)
			% q;

		return signature.r == v;
	}
	else return false;
}

large_uint DSA_System::get_subliminal_message(const large_uint signer_private_key, const large_uint &message_hash, const DSA_signature signature)
{
	return large_uint::mult_m
			(
				signature.s.inv(q), 
						
				large_uint::add_m
				(
					message_hash, 
					large_uint::mult_m(signer_private_key, signature.r, q),
					q
				),
				q
			);
}

#include <algorithm>
DSA_System::~DSA_System()
{
	std::for_each(_signers.begin(), _signers.end(), [](DSA_signer* signer) mutable
	{
		delete signer;
	});
}

#endif  /* DSA_SYSTEM_CPP */  
